package roaring

import (
	
	
	
	
	

	
)

type container interface {
	// addOffset returns the (low, high) parts of the shifted container.
	// Whenever one of them would be empty, nil will be returned instead to
	// avoid unnecessary allocations.
	addOffset(uint16) (container, container)

	clone() container
	and(container) container
	andCardinality(container) int
	iand(container) container // i stands for inplace
	andNot(container) container
	iandNot(container) container // i stands for inplace
	isEmpty() bool
	getCardinality() int
	// rank returns the number of integers that are
	// smaller or equal to x. rank(infinity) would be getCardinality().
	rank(uint16) int

	// getCardinalityInRange returns the number of integers that are
	// within the half-open range [start, end). It is equivalent to
	// rank(end-1) - rank(start-1) but may be faster.
	getCardinalityInRange(start, end uint) int

	iadd(x uint16) bool                   // inplace, returns true if x was new.
	iaddReturnMinimized(uint16) container // may change return type to minimize storage.

	iaddRange(start, endx int) container // i stands for inplace, range is [firstOfRange,endx)

	iremove(x uint16) bool                   // inplace, returns true if x was present.
	iremoveReturnMinimized(uint16) container // may change return type to minimize storage.

	not(start, final int) container        // range is [firstOfRange,lastOfRange)
	inot(firstOfRange, endx int) container // i stands for inplace, range is [firstOfRange,endx)
	xor(r container) container
	ixor(r container) container // i stands for inplace
	getShortIterator() shortPeekable
	getUnsetIterator() shortPeekable
	iterate(cb func(x uint16) bool) bool
	getReverseIterator() shortIterable
	getManyIterator() manyIterable
	contains(i uint16) bool
	maximum() uint16
	minimum() uint16

	// equals is now logical equals; it does not require the
	// same underlying container types, but compares across
	// any of the implementations.
	equals(r container) bool

	fillLeastSignificant16bits(array []uint32, i int, mask uint32) int
	or(r container) container
	orCardinality(r container) int
	isFull() bool
	ior(r container) container   // i stands for inplace
	intersects(r container) bool // whether the two containers intersect
	lazyOR(r container) container
	lazyIOR(r container) container
	getSizeInBytes() int
	iremoveRange(start, final int) container // i stands for inplace, range is [firstOfRange,lastOfRange)
	selectInt(x uint16) int                  // selectInt returns the xth integer in the container
	serializedSizeInBytes() int
	writeTo(io.Writer) (int, error)

	numberOfRuns() int
	toEfficientContainer() container
	String() string
	containerType() contype

	safeMinimum() (uint16, error)
	safeMaximum() (uint16, error)
	nextValue(x uint16) int
	previousValue(x uint16) int
	nextAbsentValue(x uint16) int
	previousAbsentValue(x uint16) int
	validate() error
}

type contype uint8

const (
	bitmapContype contype = iota
	arrayContype
	run16Contype
	run32Contype
)

var (
	ErrKeySortOrder          = errors.New("keys were out of order")
	ErrCardinalityConstraint = errors.New("size of arrays was not coherent")
)

// careful: range is [firstOfRange,lastOfRange]
func rangeOfOnes(,  int) container {
	if  > MaxUint16 {
		panic("rangeOfOnes called with start > MaxUint16")
	}
	if  > MaxUint16 {
		panic("rangeOfOnes called with last > MaxUint16")
	}
	if  < 0 {
		panic("rangeOfOnes called with start < 0")
	}
	if  < 0 {
		panic("rangeOfOnes called with last < 0")
	}
	return newRunContainer16Range(uint16(), uint16()).toEfficientContainer()
}

type roaringArray struct {
	keys            []uint16
	containers      []container `msg:"-"` // don't try to serialize directly.
	needCopyOnWrite []bool
	copyOnWrite     bool
}

func newRoaringArray() *roaringArray {
	return &roaringArray{}
}

// runOptimize compresses the element containers to minimize space consumed.
// Q: how does this interact with copyOnWrite and needCopyOnWrite?
// A: since we aren't changing the logical content, just the representation,
//
//	we don't bother to check the needCopyOnWrite bits. We replace
//	(possibly all) elements of ra.containers in-place with space
//	optimized versions.
func ( *roaringArray) () {
	for  := range .containers {
		.containers[] = .containers[].toEfficientContainer()
	}
}

func ( *roaringArray) ( uint16,  container,  bool) {
	.keys = append(.keys, )
	.containers = append(.containers, )
	.needCopyOnWrite = append(.needCopyOnWrite, )
}

func ( *roaringArray) ( roaringArray,  int) {
	 := .needCopyOnWrite[]
	.appendContainer(.keys[], .containers[], )
}

func ( *roaringArray) ( roaringArray,  int) {
	// cow only if the two request it, or if we already have a lightweight copy
	 := (.copyOnWrite && .copyOnWrite) || .needsCopyOnWrite()
	if ! {
		// since there is no copy-on-write, we need to clone the container (this is important)
		.appendContainer(.keys[], .containers[].clone(), )
	} else {
		.appendContainer(.keys[], .containers[], )
		if !.needsCopyOnWrite() {
			.setNeedsCopyOnWrite()
		}
	}
}

func ( *roaringArray) ( roaringArray, ,  int) {
	for  := ;  < ; ++ {
		.appendWithoutCopy(, )
	}
}

func ( *roaringArray) ( roaringArray, ,  int) {
	for  := ;  < ; ++ {
		.appendCopy(, )
	}
}

func ( *roaringArray) ( roaringArray,  uint16) {
	// cow only if the two request it, or if we already have a lightweight copy
	 := .copyOnWrite && .copyOnWrite

	for  := 0;  < .size(); ++ {
		if .keys[] >=  {
			break
		}
		 :=  || .needsCopyOnWrite()
		if  {
			.appendContainer(.keys[], .containers[], )
			if !.needsCopyOnWrite() {
				.setNeedsCopyOnWrite()
			}

		} else {
			// since there is no copy-on-write, we need to clone the container (this is important)
			.appendContainer(.keys[], .containers[].clone(), )
		}
	}
}

func ( *roaringArray) ( roaringArray,  uint16) {
	// cow only if the two request it, or if we already have a lightweight copy
	 := .copyOnWrite && .copyOnWrite

	 := .getIndex()
	if  >= 0 {
		++
	} else {
		 = - - 1
	}

	for  := ;  < .size(); ++ {
		 :=  || .needsCopyOnWrite()
		if  {
			.appendContainer(.keys[], .containers[], )
			if !.needsCopyOnWrite() {
				.setNeedsCopyOnWrite()
			}
		} else {
			// since there is no copy-on-write, we need to clone the container (this is important)
			.appendContainer(.keys[], .containers[].clone(), )
		}
	}
}

func ( *roaringArray) (,  int) {
	if  <=  {
		return
	}

	 :=  - 

	copy(.keys[:], .keys[:])
	copy(.containers[:], .containers[:])
	copy(.needCopyOnWrite[:], .needCopyOnWrite[:])

	.resize(len(.keys) - )
}

func ( *roaringArray) ( int) {
	for  := ;  < len(.containers); ++ {
		.containers[] = nil
	}

	.keys = .keys[:]
	.containers = .containers[:]
	.needCopyOnWrite = .needCopyOnWrite[:]
}

func ( *roaringArray) () {
	.resize(0)
	.copyOnWrite = false
}

func ( *roaringArray) () *roaringArray {
	 := roaringArray{}
	.copyOnWrite = .copyOnWrite

	// this is where copyOnWrite is used.
	if .copyOnWrite {
		.keys = make([]uint16, len(.keys))
		copy(.keys, .keys)
		.containers = make([]container, len(.containers))
		copy(.containers, .containers)
		.needCopyOnWrite = make([]bool, len(.needCopyOnWrite))

		.markAllAsNeedingCopyOnWrite()
		.markAllAsNeedingCopyOnWrite()

		// sa.needCopyOnWrite is shared
	} else {
		// make a full copy

		.keys = make([]uint16, len(.keys))
		copy(.keys, .keys)

		.containers = make([]container, len(.containers))
		for  := range .containers {
			.containers[] = .containers[].clone()
		}

		.needCopyOnWrite = make([]bool, len(.needCopyOnWrite))
	}
	return &
}

// clone all containers which have needCopyOnWrite set to true
// This can be used to make sure it is safe to munmap a []byte
// that the roaring array may still have a reference to.
func ( *roaringArray) () {
	for ,  := range .needCopyOnWrite {
		if  {
			.containers[] = .containers[].clone()
			.needCopyOnWrite[] = false
		}
	}
}

// unused function:
//func (ra *roaringArray) containsKey(x uint16) bool {
//	return (ra.binarySearch(0, int64(len(ra.keys)), x) >= 0)
//}

// getContainer returns the container with key `x`
// if no such container exists `nil` is returned
func ( *roaringArray) ( uint16) container {
	 := .binarySearch(0, int64(len(.keys)), )
	if  < 0 {
		return nil
	}
	return .containers[]
}

func ( *roaringArray) ( int) container {
	return .containers[]
}

func ( *roaringArray) ( int,  bool) container {
	 := .getContainerAtIndex()
	switch t := .(type) {
	case *arrayContainer:
		 = .toBitmapContainer()
	case *runContainer16:
		if !.isFull() {
			 = .toBitmapContainer()
		}
	case *bitmapContainer:
		if  && .needCopyOnWrite[] {
			 = .containers[].clone()
		}
	}
	return 
}

// getUnionedWritableContainer switches behavior for in-place Or
// depending on whether the container requires a copy on write.
// If it does using the non-inplace or() method leads to fewer allocations.
func ( *roaringArray) ( int,  container) container {
	if .needCopyOnWrite[] {
		return .getContainerAtIndex().or()
	}
	return .getContainerAtIndex().ior()
}

func ( *roaringArray) ( int) container {
	if .needCopyOnWrite[] {
		.containers[] = .containers[].clone()
		.needCopyOnWrite[] = false
	}
	return .containers[]
}

// getIndex returns the index of the container with key `x`
// if no such container exists a negative value is returned
func ( *roaringArray) ( uint16) int {
	// Todo : test
	// before the binary search, we optimize for frequent cases
	 := len(.keys)
	if ( == 0) || (.keys[-1] == ) {
		return  - 1
	}
	return .binarySearch(0, int64(), )
}

func ( *roaringArray) ( int) uint16 {
	return .keys[]
}

func ( *roaringArray) ( int,  uint16,  container) {
	.keys = append(.keys, 0)
	.containers = append(.containers, nil)

	copy(.keys[+1:], .keys[:])
	copy(.containers[+1:], .containers[:])

	.keys[] = 
	.containers[] = 

	.needCopyOnWrite = append(.needCopyOnWrite, false)
	copy(.needCopyOnWrite[+1:], .needCopyOnWrite[:])
	.needCopyOnWrite[] = false
}

func ( *roaringArray) ( uint16) bool {
	 := .binarySearch(0, int64(len(.keys)), )
	if  >= 0 { // if a new key
		.removeAtIndex()
		return true
	}
	return false
}

func ( *roaringArray) ( int) {
	copy(.keys[:], .keys[+1:])
	copy(.containers[:], .containers[+1:])

	copy(.needCopyOnWrite[:], .needCopyOnWrite[+1:])

	.resize(len(.keys) - 1)
}

func ( *roaringArray) ( int,  container) {
	.containers[] = 
}

func ( *roaringArray) ( int,  uint16,  container,  bool) {
	.keys[] = 
	.containers[] = 
	.needCopyOnWrite[] = 
}

func ( *roaringArray) () int {
	return len(.keys)
}

// binarySearch returns the index of the key.
// negative value returned if not found
func ( *roaringArray) (,  int64,  uint16) int {
	// TODO: add unit tests
	 := 
	 :=  - 1
	for +16 <=  {
		 :=  + (-)/2 // avoid overflow
		 := .keys[]

		if  <  {
			 =  + 1
		} else if  >  {
			 =  - 1
		} else {
			return int()
		}
	}
	for ;  <= ; ++ {
		 := .keys[]
		if  >=  {
			if  ==  {
				return int()
			}
			break
		}
	}
	return -int( + 1)
}

func ( *roaringArray) ( interface{}) bool {
	,  := .(roaringArray)
	if  {

		if .size() != .size() {
			return false
		}
		for ,  := range .keys {
			if  != .keys[] {
				return false
			}
		}

		for ,  := range .containers {
			if !.equals(.containers[]) {
				return false
			}
		}
		return true
	}
	return false
}

func ( *roaringArray) () uint64 {
	 := uint64(len(.keys))
	if .hasRunCompression() {
		if  < noOffsetThreshold { // for small bitmaps, we omit the offsets
			return 4 + (+7)/8 + 4*
		}
		return 4 + (+7)/8 + 8* // - 4 because we pack the size with the cookie
	}
	return 4 + 4 + 8*
}

// should be dirt cheap
func ( *roaringArray) () uint64 {
	 := .headerSize()
	for ,  := range .containers {
		 += uint64(.serializedSizeInBytes())
	}
	return 
}

// spec: https://github.com/RoaringBitmap/RoaringFormatSpec
func ( *roaringArray) ( io.Writer) ( int64,  error) {
	 := .hasRunCompression()
	 := 0
	 := 8
	if  {
		 = 4
		 = (len(.keys) + 7) / 8
	}
	 := 4 * len(.keys)
	 :=  +  + 

	 := make([]byte, +4*len(.keys))

	 := 0

	if  {
		binary.LittleEndian.PutUint16([0:], uint16(serialCookie))
		 += 2
		binary.LittleEndian.PutUint16([2:], uint16(len(.keys)-1))
		 += 2
		// compute isRun bitmap without temporary allocation
		 := [ : +]
		for ,  := range .containers {
			switch .(type) {
			case *runContainer16:
				[/8] |= 1 << (uint() % 8)
			}
		}
		 += 
	} else {
		binary.LittleEndian.PutUint32([0:], uint32(serialCookieNoRunContainer))
		 += 4
		binary.LittleEndian.PutUint32([4:], uint32(len(.keys)))
		 += 4
	}

	// descriptive header
	for ,  := range .keys {
		binary.LittleEndian.PutUint16([:], )
		 += 2
		 := .containers[]
		binary.LittleEndian.PutUint16([:], uint16(.getCardinality()-1))
		 += 2
	}

	 := int64( + 4*len(.keys))
	if ! || (len(.keys) >= noOffsetThreshold) {
		// offset header
		for ,  := range .containers {
			binary.LittleEndian.PutUint32([:], uint32())
			 += 4
			switch rc := .(type) {
			case *runContainer16:
				 += 2 + int64(len(.iv))*4
			default:
				 += int64(getSizeInBytesFromCardinality(.getCardinality()))
			}
		}
	}

	,  := .Write([:])
	if  != nil {
		return , 
	}
	 += int64()

	for ,  := range .containers {
		,  := .writeTo()
		if  != nil {
			return , 
		}
		 += int64()
	}
	return , nil
}

// spec: https://github.com/RoaringBitmap/RoaringFormatSpec
func ( *roaringArray) () ([]byte, error) {
	var  bytes.Buffer
	,  := .writeTo(&)
	return .Bytes(), 
}

// Reads a serialized roaringArray from a byte slice.
func ( *roaringArray) ( internal.ByteInput,  ...byte) (int64, error) {
	var  uint32
	var  error
	if len() > 0 && len() != 4 {
		return int64(len()), fmt.Errorf("error in roaringArray.readFrom: could not read initial cookie: incorrect size of cookie header")
	}
	if len() == 4 {
		 = binary.LittleEndian.Uint32()
	} else {
		,  = .ReadUInt32()
		if  != nil {
			return .GetReadBytes(), fmt.Errorf("error in roaringArray.readFrom: could not read initial cookie: %s", )
		}
	}
	// If NextReturnsSafeSlice is false, then willNeedCopyOnWrite should be true
	 := !.NextReturnsSafeSlice()

	var  uint32
	var  []byte

	if &0x0000FFFF == serialCookie {
		 = >>16 + 1
		// create is-run-container bitmap
		 := (int() + 7) / 8
		,  = .Next()
		if  != nil {
			return .GetReadBytes(), fmt.Errorf("malformed bitmap, failed to read is-run bitmap, got: %s", )
		}
	} else if  == serialCookieNoRunContainer {
		,  = .ReadUInt32()
		if  != nil {
			return .GetReadBytes(), fmt.Errorf("malformed bitmap, failed to read a bitmap size: %s", )
		}
	} else {
		return .GetReadBytes(), fmt.Errorf("error in roaringArray.readFrom: did not find expected serialCookie in header")
	}

	if  > (1 << 16) {
		return .GetReadBytes(), fmt.Errorf("it is logically impossible to have more than (1<<16) containers")
	}

	// descriptive header
	,  := .Next(2 * 2 * int())
	if  != nil {
		return .GetReadBytes(), fmt.Errorf("failed to read descriptive header: %s", )
	}

	 := byteSliceAsUint16Slice()

	if  == nil ||  >= noOffsetThreshold {
		if  := .SkipBytes(int() * 4);  != nil {
			return .GetReadBytes(), fmt.Errorf("failed to skip bytes: %s", )
		}
	}

	// Allocate slices upfront as number of containers is known
	if cap(.containers) >= int() {
		.containers = .containers[:]
	} else {
		.containers = make([]container, )
	}

	if cap(.keys) >= int() {
		.keys = .keys[:]
	} else {
		.keys = make([]uint16, )
	}

	if cap(.needCopyOnWrite) >= int() {
		.needCopyOnWrite = .needCopyOnWrite[:]
	} else {
		.needCopyOnWrite = make([]bool, )
	}

	for  := uint32(0);  < ; ++ {
		 := [2*]
		 := int([2*+1]) + 1
		.keys[] = 
		.needCopyOnWrite[] = 

		if  != nil && [/8]&(1<<(%8)) != 0 {
			// run container
			,  := .ReadUInt16()
			if  != nil {
				return 0, fmt.Errorf("failed to read runtime container size: %s", )
			}

			,  := .Next(int() * 4)
			if  != nil {
				return .GetReadBytes(), fmt.Errorf("failed to read runtime container content: %s", )
			}

			 := runContainer16{
				iv: byteSliceAsInterval16Slice(),
			}

			.containers[] = &
		} else if  > arrayDefaultMaxSize {
			// bitmap container
			,  := .Next(arrayDefaultMaxSize * 2)
			if  != nil {
				return .GetReadBytes(), fmt.Errorf("failed to read bitmap container: %s", )
			}

			 := bitmapContainer{
				cardinality: ,
				bitmap:      byteSliceAsUint64Slice(),
			}

			.containers[] = &
		} else {
			// array container
			,  := .Next( * 2)
			if  != nil {
				return .GetReadBytes(), fmt.Errorf("failed to read array container: %s", )
			}

			 := arrayContainer{
				byteSliceAsUint16Slice(),
			}

			.containers[] = &
		}
	}

	return .GetReadBytes(), nil
}

func ( *roaringArray) () bool {
	for ,  := range .containers {
		switch .(type) {
		case *runContainer16:
			return true
		}
	}
	return false
}

/**
 * Find the smallest integer index larger than pos such that array[index].key&gt;=min. If none can
 * be found, return size. Based on code by O. Kaser.
 *
 * @param min minimal value
 * @param pos index to exceed
 * @return the smallest index greater than pos such that array[index].key is at least as large as
 *         min, or size if it is not possible.
 */
func ( *roaringArray) ( uint16,  int) int {
	 :=  + 1

	if  >= len(.keys) || .keys[] >=  {
		return 
	}

	 := 1

	for + < len(.keys) && .keys[+] <  {
		 *= 2
	}
	var  int
	if + < len(.keys) {
		 =  + 
	} else {
		 = len(.keys) - 1
	}

	if .keys[] ==  {
		return 
	}

	if .keys[] <  {
		// means
		// array
		// has no
		// item
		// >= min
		// pos = array.length;
		return len(.keys)
	}

	// we know that the next-smallest span was too small
	 += ( >> 1)

	 := 0
	for +1 !=  {
		 = ( + ) >> 1
		if .keys[] ==  {
			return 
		} else if .keys[] <  {
			 = 
		} else {
			 = 
		}
	}
	return 
}

func ( *roaringArray) () {
	for  := range .needCopyOnWrite {
		.needCopyOnWrite[] = true
	}
}

func ( *roaringArray) ( int) bool {
	return .needCopyOnWrite[]
}

func ( *roaringArray) ( int) {
	.needCopyOnWrite[] = true
}

func ( *roaringArray) () bool {
	if len(.keys) == 0 || len(.keys) == 1 {
		return true
	}
	 := .keys[0]
	for  := 1;  < len(.keys); ++ {
		 := .keys[]
		if  >=  {
			return false
		}
		 = 

	}
	return true
}

// validate checks the referential integrity
// ensures len(keys) == len(containers), recurses and checks each container type
func ( *roaringArray) () error {
	if !.checkKeysSorted() {
		return ErrKeySortOrder
	}

	if len(.keys) != len(.containers) {
		return ErrCardinalityConstraint
	}

	if len(.keys) != len(.needCopyOnWrite) {
		return ErrCardinalityConstraint
	}

	for ,  := range .containers {
		 := .validate()
		if  != nil {
			return 
		}
	}

	return nil
}